package com.flexrrb.controls
{
	import com.flexrrb.controls.groupTextInputClasses.GroupTextInputItem;
	import com.flexrrb.controls.groupTextInputClasses.SimpleGroupTextInputValidator;
	import com.flexrrb.core.IGroupTextInputValidator;
	import com.flexrrb.events.GroupTextInputEvent;
	
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	
	import mx.collections.ArrayCollection;
	import mx.controls.TextInput;
	import mx.core.EdgeMetrics;
	import mx.core.IRectangularBorder;
	import mx.core.UIComponent;
	import mx.core.mx_internal;
	import mx.styles.CSSStyleDeclaration;
	import mx.styles.StyleManager;
	use namespace mx_internal;
	
	//[Style(name="validator", type=
	[Style(name="itemPadding", type="Number", format="length")]
	[Style(name="validator", type="Class")]
	
	public class GroupTextInput extends TextInput
	{
		private var _items:ArrayCollection;
		private var _itemRemoved:Boolean;
		private var _itemAdded:Boolean;
		private var _totalWidth:Number;
		private var _itemPadding:Number;
		private var _dataSet:ArrayCollection;
		private var _validator:IGroupTextInputValidator;
		
		private var _removeKeyCode:uint = Keyboard.BACKSPACE;
		private var _separatorKeyCode:uint = Keyboard.SPACE;
		
		private var _originalHeight:Number = NaN;
		private var _originalTextFieldHeight:Number = NaN;
		
		private var _invalidateHeight:Boolean;
		
		private static var classConstructed:Boolean = constructClass();
		
		private static function constructClass():Boolean
		{
			var selector:CSSStyleDeclaration = StyleManager.getStyleDeclaration("GroupTextInput");
			if(!selector)
			{
				selector = new CSSStyleDeclaration();
			}
			
			selector.defaultFactory = function():void
			{
				this.itemPadding = 2;
				this.validator = SimpleGroupTextInputValidator;
			}
			
			StyleManager.setStyleDeclaration("GroupTextInput", selector, false);
			
			return true;
		}
		
		public function GroupTextInput()
		{
			super();
			_totalWidth = 0;
			_items = new ArrayCollection();
		}
		
		public function removeAllItems():void
		{
			var item:UIComponent;
			while(_items.length > 0)
			{
				item = _items.removeItemAt(0) as UIComponent;
				this.removeChild(item);
			}
			
			_itemRemoved = true;
			invalidateDisplayList();
		}
		
		public function get removeKeyCode():uint
		{
			return _removeKeyCode;
		}
		
		public function set removeKeyCode(keyCode:uint):void
		{
			_removeKeyCode = keyCode;
		}
		
		public function get separateKeyCode():uint
		{
			return _separatorKeyCode;
		}
		
		public function set separateKeyCode(keyCode:uint):void
		{
			_separatorKeyCode = keyCode;
		}
		
		public function get validator():IGroupTextInputValidator
		{
			return _validator;
		}
		
		public function set validator(newValidator:IGroupTextInputValidator):void
		{
			_validator = newValidator;
		}
		
		public function get dataProvider():ArrayCollection
		{
			return _dataSet;
		}
		
		public function set dataProvider(value:ArrayCollection):void
		{
			_dataSet = value;
			if(_dataSet)
			{
				this.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false, 0, true);
				this.addEventListener(KeyboardEvent.KEY_UP, onKeyUp, false, 0, true);
			}
			else
			{
				this.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
				this.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
			}
		}
		
		private function onKeyDown(event:KeyboardEvent):void
		{
			if(event.keyCode == removeKeyCode && textField.length == 0)
			{
				highlightItems();
			}
		}
		
		private function onKeyUp(event:KeyboardEvent):void
		{
			trace("on up normal ", textField.text);
			if(event.keyCode == separateKeyCode)
			{
				validateInput();
			}
		}
		
		private function highlightItems():void
		{
			if(_items.length > 0)
			{
				var item:GroupTextInputItem = _items[_items.length - 1] as GroupTextInputItem;
				trace("set focus in highlightItems");
				item.setFocus();
				invalidateDisplayList();
			}
		}
		
		private function validateInput():void
		{
			var text:String = textField.text.substring(0, textField.text.length - 1);
			if(validator.validateText(text, _dataSet))
			{
				addItemRenderer();
			}
		}
		
		private function addItemRenderer():void
		{
			var item:GroupTextInputItem = new GroupTextInputItem();
			item.text = textField.text;
			
			var remaindingWidth:Number = (this.width - 4) - (_totalWidth % (this.width - 4));
			
			if(_items.length > 0)
				remaindingWidth -= 2;
			
			item.maxWidth = remaindingWidth;
			
			item.addEventListener(GroupTextInputEvent.REMOVE_ITEM, removeItemRenderer, false, 0, true);
			
			_items.addItem(item);
			addChild(item);
			
			_itemAdded = true;
			//invalidateProperties();
			invalidateSize();
		}
		
		private var _removedItem:UIComponent;
		private function removeItemRenderer(event:GroupTextInputEvent):void
		{
			_removedItem = _items.removeItemAt(_items.getItemIndex(event.currentTarget)) as UIComponent;
			_removedItem.removeEventListener(GroupTextInputEvent.REMOVE_ITEM, removeItemRenderer);
			if(_removedItem.width == (this.width - 4))
			{
				_totalWidth -= _removedItem.width;
			}
			else
			{
				_totalWidth -= (_removedItem.width + _itemPadding);
			}
			
			this.removeChild(_removedItem);
			_itemRemoved = true;
			
			textField.setFocus();
			
			invalidateSize();
			invalidateDisplayList();
		}
		
		override public function stylesInitialized():void
		{
			super.stylesInitialized();
			_itemPadding = this.getStyle("itemPadding") as Number;
			
			var validatorClass:Class = getStyle("validator");
			if(validatorClass)
			{
				this.validator = new validatorClass();
			}
			else
			{
				this.validator = new SimpleGroupTextInputValidator();
			}
		}
		
		override protected function commitProperties():void
		{
			super.commitProperties();
						
			if(_itemRemoved)
			{
				if(numChildren > 0)
				{
					if(height > _originalHeight)
					{
						if(_totalWidth == 0)
						{
							this.height = height - _originalHeight;
							this.setActualSize(width, height - _originalHeight);
						}
					}
					
					_totalWidth = (this.width - 4) - _removedItem.width;
					_removedItem = null;
				}
			}
		}
		
		override protected function measure():void
		{
			super.measure();
			
			var item:UIComponent;
			
			measuredHeight = 22;
			
			if(_itemAdded)
			{
				item = _items[_items.length - 1] as UIComponent;
				
				if(item)
				{
					measuredHeight = height;
					
					var xPos:Number = _totalWidth % (width - 4) + _itemPadding;
					var rows:int = Math.floor(_totalWidth / (width - 4)) + 1;
					var yPos:Number = (rows - 1) * _originalHeight;
					
					if(yPos == 0)
						yPos += _itemPadding;
					 
					measuredHeight = _originalHeight * rows;
					
					item.move(xPos, yPos);
					
					_totalWidth += _itemPadding + item.measuredWidth;
					
					if(xPos + item.measuredWidth >= (this.width - 4))
					{
						rows++;
					}
					
					measuredHeight = rows * _originalHeight;
					
				}
			}
			else if(_itemRemoved)
			{
				measuredHeight = height;
				if(numChildren > 0)
				{
					var rows:int = _totalWidth / (this.width - 4);
					rows++;
					
					measuredHeight = rows * _originalHeight;
				}
				_removedItem = null;
			}
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			var item:UIComponent;
			
			if(isNaN(_originalHeight))
			{
				_originalHeight = unscaledHeight;
			}
			
			if(isNaN(_originalTextFieldHeight))
			{
				_originalTextFieldHeight = textField.height;
			}
			
			if(_itemAdded)
			{
				item = _items[_items.length - 1] as UIComponent;
				item.setActualSize(item.measuredWidth, item.measuredHeight);
				textField.text = "";
				
				item.visible = true;
				_itemAdded = false;
			}
			else if(_itemRemoved)
			{
				_itemRemoved = false;
			}
			
			var paddingBottom:Number = getStyle("paddingBottom");
			var paddingTop:Number = getStyle("paddingTop");
			var bm:EdgeMetrics
			
			if (border)
	        {
	            bm = border is IRectangularBorder ?
	                    IRectangularBorder(border).borderMetrics : EdgeMetrics.EMPTY;
	        }
	        else
	        {
	            bm = EdgeMetrics.EMPTY;
	        }
			
			if(bm)
			{
				paddingBottom += bm.bottom;
			}
			
			if(textField.height != _originalTextFieldHeight)
			{
				textField.height = _originalTextFieldHeight;
			}
			
			var textFieldXPos:Number = _totalWidth % (this.width - 4);
			textField.move(textFieldXPos + _itemPadding, height - paddingBottom - textField.height);
			textField.width = this.width - 2 - textField.x;
		} 
	}
}